如何在业务中体现 TCC 事务模型?
0. 引言
TCC(Try-Confirm-Cancel)是分布式事务中的"业务补偿派"代表:把每个资源操作拆成预留(Try)、确认(Confirm)、取消(Cancel)三个业务方法,由事务管理器统一编排。相比 2PC 的"数据库锁资源",TCC 把资源控制权交给业务代码——更灵活、性能更好,但侵入性也最高。本文用转账场景讲透 TCC 的流程与三大难题。
1. TCC 的核心思想
图表渲染中…
| 方法 | 语义 | 转账示例(账户 A → B 转 100) |
|---|---|---|
| Try | 尝试:预留资源,保证 Cancel 或 Confirm 可执行 | A 余额扣减到"冻结"字段;B 增加"预收"字段 |
| Confirm | 确认:Try 成功后真正执行(幂等) | A 冻结转扣减;B 预收转入账 |
| Cancel | 取消:释放 Try 预留的资源(幂等) | A 冻结回余额;B 预收清零 |
关键特征:Try 不真正扣减,只是"占位"——这样 Confirm/Cancel 都基于 Try 的预留结果执行,全局事务管理器可以安全地决定提交或回滚。
2. TCC 完整流程(转账示例)
图表渲染中…
- 所有 Try 成功 → 全局 Confirm;任一 Try 失败 → 全局 Cancel;
- 每个方法必须幂等(Confirm/Cancel 可能被重试);
- 事务管理器负责记录全局状态、驱动各分支、处理超时重试。
3. TCC 的三大难题
| 难题 | 场景 | 解法 |
|---|---|---|
| 空回滚 | Try 因网络超时未到达,但 Cancel 先到了——Cancel 执行时资源从未被预留 | 用事务控制表记录分支状态:Cancel 前检查 Try 是否执行过,未执行则直接返回成功并记录"已空回滚" |
| 幂等 | Confirm/Cancel 因网络重试被重复执行——重复扣款/重复入账 | 唯一事务 ID + 状态机:同一分支只执行一次 Confirm/Cancel(幂等表/状态字段) |
| 悬挂 | Try 超时被 Cancel(空回滚),但 Try 请求延迟到达并执行了预留——资源被永久冻结 | 事务控制表中记录"已空回滚",Try 到达时发现已回滚则拒绝执行(防悬挂) |
text
典型时序(悬挂问题):
① Try 发送超时 → ② TM 判定失败 → ③ Cancel 执行(空回滚,记录状态)
→ ④ 迟到的 Try 到达 → 必须拒绝(否则资源被冻结且无人释放)三者合起来要求:Try、Confirm、Cancel 都要访问"事务控制表"做状态校验——这是 TCC 落地的最大工作量,也是框架(Seata)帮你做的事情之一。
4. TCC vs 2PC vs 普通补偿
| 维度 | 2PC/XA | TCC | 普通补偿(Saga) |
|---|---|---|---|
| 资源控制 | 数据库锁(资源级) | 业务冻结(业务级) | 无预留,直接执行再回补 |
| 一致性 | 强一致 | 最终一致(Try 后可见中间态) | 最终一致 |
| 侵入性 | 低(SQL 级) | 高(三方法 + 控制表) | 中(补偿逻辑) |
| 性能 | 低(锁等待) | 中(无长锁,但多轮调用) | 高(异步) |
| 适用 | 低并发跨库 | 资金类强管控 | 长流程可异步 |
5. Seata 中的 TCC 落地
java
@LocalTCC
public interface AccountAction {
@TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirmDeduct", rollbackMethod = "cancelDeduct")
boolean tryDeduct(@BusinessActionContextParameter(paramName = "accountId") String accountId,
@BusinessActionContextParameter(paramName = "amount") BigDecimal amount);
boolean confirmDeduct(BusinessActionContext ctx);
boolean cancelDeduct(BusinessActionContext ctx);
}@LocalTCC+@TwoPhaseBusinessAction声明三方法,Seata 自动管理空回滚/幂等/悬挂的控制表(branch_table);- Confirm/Cancel 由 Seata 在全局事务提交/回滚时自动调用(含重试与幂等);
- 业务只需关注三方法的业务实现,框架解决状态难题。
6. 小结
- TCC = Try 预留 → Confirm 确认 / Cancel 取消,资源控制下沉到业务层;
- 三大难题是落地的试金石:空回滚、幂等、悬挂,统一靠"事务控制表 + 状态机"解决;
- TCC 适合资金类强管控:中间态可控(冻结/预收)、无长锁、最终一致;
- 框架(Seata/ByteTCC)承担状态管理,业务侧重点是三方法的正确性与幂等实现。
下一章讲解分布式锁的应用场景与实现方案对比:数据库、Redis、ZooKeeper、etcd。